/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#include "lib/number/ob_number_v2.h"
#include "share/schema/ob_column_schema.h"

#define VARIABLE_BUF_LEN 128

#define COMPARE_VALUE(obj_get_fun, medium_type, value, exist)            \
  {                                                                      \
    medium_type tmp_value = 0;                                           \
    tmp_value = obj.obj_get_fun();                                       \
    exist = tmp_value == static_cast<medium_type>(value) ? true : false; \
    if (!exist) {                                                        \
      STORAGE_LOG(WARN, "value is different", K(tmp_value), K(value));   \
    }                                                                    \
  }

#define COMPARE_NUMBER(allocator, obj_get_fun, value, exist)                           \
  {                                                                                    \
    ObNumber number;                                                                   \
    char* buf = NULL;                                                                  \
    if (NULL == (buf = reinterpret_cast<char*>(allocator->alloc(VARIABLE_BUF_LEN)))) { \
      ret = OB_ALLOCATE_MEMORY_FAILED;                                                 \
      STORAGE_LOG(WARN, "fail to alloc memory");                                       \
    } else {                                                                           \
      snprintf(buf, VARIABLE_BUF_LEN, "%ld", value);                                   \
    }                                                                                  \
    if (OB_SUCC(ret)) {                                                                \
      if (OB_SUCCESS != (ret = number.from(buf, *allocator))) {                        \
        STORAGE_LOG(WARN, "fail to format num", K(ret));                               \
      } else if (number != obj.obj_get_fun()) {                                        \
        exist = false;                                                                 \
        STORAGE_LOG(WARN, "row value is different", K(obj), K(number));                \
      }                                                                                \
    }                                                                                  \
  }

#define SET_VALUE(rowkey_pos, obj_set_fun, type, seed, value) \
  {                                                           \
    if (rowkey_pos > 0) {                                     \
      obj.obj_set_fun(static_cast<type>(seed));               \
    } else {                                                  \
      obj.obj_set_fun(static_cast<type>(value));              \
    }                                                         \
  }

#define SET_CHAR(allocator, rowkey_pos, obj_set_fun, seed, value)                      \
  {                                                                                    \
    char* buf = NULL;                                                                  \
    if (NULL == (buf = reinterpret_cast<char*>(allocator->alloc(VARIABLE_BUF_LEN)))) { \
      ret = OB_ALLOCATE_MEMORY_FAILED;                                                 \
      STORAGE_LOG(WARN, "fail to alloc memory");                                       \
    } else if (rowkey_pos > 0) {                                                       \
      snprintf(buf, VARIABLE_BUF_LEN, "%064ld", seed);                                 \
    } else {                                                                           \
      snprintf(buf, VARIABLE_BUF_LEN, "%064ld", value);                                \
    }                                                                                  \
    if (OB_SUCC(ret)) {                                                                \
      ObString str;                                                                    \
      str.assign_ptr(buf, static_cast<int32_t>(strlen(buf)));                          \
      obj.obj_set_fun(str);                                                            \
      obj.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);                              \
    }                                                                                  \
  }

#define SET_NUMBER(allocator, rowkey_pos, obj_set_fun, seed, value)                    \
  {                                                                                    \
    ObNumber number;                                                                   \
    char* buf = NULL;                                                                  \
    if (NULL == (buf = reinterpret_cast<char*>(allocator->alloc(VARIABLE_BUF_LEN)))) { \
      ret = OB_ALLOCATE_MEMORY_FAILED;                                                 \
      STORAGE_LOG(WARN, "fail to alloc memory");                                       \
    } else if (rowkey_pos > 0) {                                                       \
      snprintf(buf, VARIABLE_BUF_LEN, "%ld", seed);                                    \
    } else {                                                                           \
      snprintf(buf, VARIABLE_BUF_LEN, "%ld", value);                                   \
    }                                                                                  \
    if (OB_SUCC(ret)) {                                                                \
      if (OB_SUCCESS != (ret = number.from(buf, *allocator))) {                        \
        STORAGE_LOG(WARN, "fail to format num", K(ret));                               \
      } else {                                                                         \
        obj.obj_set_fun(number);                                                       \
      }                                                                                \
    }                                                                                  \
  }

namespace oceanbase {
using namespace common;
using namespace storage;
using namespace number;
namespace blocksstable {

ObRowGenerate::ObRowGenerate()
    : allocator_(ObModIds::TEST),
      p_allocator_(NULL),
      schema_(),
      seed_(0),
      is_multi_version_row_(false),
      is_sparse_(false),
      is_inited_(false),
      is_reused_(false)
{}

ObRowGenerate::~ObRowGenerate()
{}

int ObRowGenerate::init(
    const share::schema::ObTableSchema& src_schema, const bool is_multi_version_row, const bool is_sparse)
{
  int ret = OB_SUCCESS;
  if (is_inited_) {
    ret = OB_INIT_TWICE;
    STORAGE_LOG(WARN, "already inited");
  } else if (!src_schema.is_valid()) {
    STORAGE_LOG(WARN, "schema is invalid.", K(src_schema));
  } else if (is_multi_version_row) {
    ObMultiVersionColDescGenerate gen;
    if (OB_FAIL(gen.init(&src_schema))) {
      STORAGE_LOG(WARN, "failed to init ObMultiVersionColDescGenerate", K(ret));
    } else if (OB_FAIL(gen.generate_column_ids(column_list_))) {
      STORAGE_LOG(WARN, "failed to init generate_column_ids", K(ret));
    }
  } else {
    if (OB_SUCCESS != (ret = src_schema.get_column_ids(column_list_))) {
      STORAGE_LOG(WARN, "fail to get column ids.", K(ret));
    }
  }
  STORAGE_LOG(INFO, "init row gen", "column_count", column_list_.count(), K(column_list_));
  if (OB_SUCC(ret)) {
    is_multi_version_row_ = is_multi_version_row;
    p_allocator_ = &allocator_;
    is_sparse_ = is_sparse;
    is_inited_ = true;
    is_reused_ = true;
    if (OB_FAIL(schema_.assign(src_schema))) {
      STORAGE_LOG(WARN, "fail to assign schema", K(ret));
    } else {
      STORAGE_LOG(INFO,
          "init row gen",
          K(is_multi_version_row),
          K(is_multi_version_row_),
          "column_count",
          column_list_.count(),
          K(column_list_));
    }
  }
  return ret;
}

int ObRowGenerate::init(const share::schema::ObTableSchema& src_schema, ObArenaAllocator* allocator,
    const bool is_multi_version_row, const bool is_sparse)
{
  int ret = OB_SUCCESS;
  if (OB_FAIL(init(src_schema, is_multi_version_row, is_sparse))) {
    STORAGE_LOG(WARN, "failed to init ObRowGenerate", K(ret));
  } else {
    p_allocator_ = allocator;
    is_reused_ = false;
  }
  return ret;
}

int ObRowGenerate::get_next_row(ObStoreRow& row)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else {
    if (is_reused_) {
      p_allocator_->reuse();
    }
    if (OB_FAIL(generate_one_row(row, seed_))) {
      STORAGE_LOG(WARN, "fail to generate one row.", K(ret), K(row));
    } else {
      ++seed_;
    }
  }
  return ret;
}

int ObRowGenerate::get_next_row(const int64_t seed, ObStoreRow& row)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else {
    if (is_reused_) {
      p_allocator_->reuse();
    }
    if (OB_FAIL(generate_one_row(row, seed))) {
      STORAGE_LOG(WARN, "fail to generate one row.", K(ret), K(row));
    }
  }
  return ret;
}
int ObRowGenerate::get_next_row(
    const int64_t seed, const int64_t trans_version, const ObRowDml first_dml, const ObRowDml dml, ObStoreRow& row)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else {
    if (is_reused_) {
      p_allocator_->reuse();
    }
    if (OB_FAIL(generate_one_row(row, seed, first_dml, dml, trans_version))) {
      STORAGE_LOG(WARN, "failed to generate_one_row", K(ret));
    }
  }
  return ret;
}

int ObRowGenerate::get_next_row(const int64_t seed, const int64_t trans_version, const storage::ObRowDml first_dml,
    const storage::ObRowDml dml, const bool is_compacted_row, const bool is_last_row, const bool is_first_row,
    storage::ObStoreRow& row)
{
  int ret = OB_SUCCESS;

  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else if (OB_FAIL(get_next_row(seed, trans_version, first_dml, dml, row))) {
    STORAGE_LOG(WARN, "failed to get next row", K(ret));
  } else {
    row.row_type_flag_.reset();
    if (is_compacted_row) {
      row.row_type_flag_.set_compacted_multi_version_row(true);
    }
    if (is_last_row) {
      row.row_type_flag_.set_last_multi_version_row(true);
    }
    if (is_first_row) {
      row.row_type_flag_.set_first_multi_version_row(true);
    }
  }
  return ret;
}

int ObRowGenerate::get_next_row(const int64_t seed, const common::ObArray<uint64_t>& nop_column_idxs, ObStoreRow& row)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!is_inited_)) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "ObRowGenerate has not been inited", K(ret));
  } else {
    if (is_reused_) {
      p_allocator_->reuse();
    }
    if (OB_FAIL(generate_one_row(row, seed))) {
      STORAGE_LOG(WARN, "fail to generate one row", K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < nop_column_idxs.count(); ++i) {
        const uint64_t idx = nop_column_idxs.at(i);
        row.row_val_.cells_[idx].set_nop_value();
      }
    }
  }
  return ret;
}

int ObRowGenerate::generate_one_row(
    ObStoreRow& row, const int64_t seed, const ObRowDml first_dml, const ObRowDml dml, const int64_t trans_version)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else if ((!is_multi_version_row_ && schema_.get_column_count() != row.row_val_.count_) ||
             (is_sparse_ && OB_ISNULL(row.column_ids_))) {
    ret = OB_INVALID_ARGUMENT;
    STORAGE_LOG(WARN,
        "invalid argument.",
        K(schema_.get_column_count()),
        K(row.row_val_.count_),
        K(is_sparse_),
        K(row.column_ids_));
  } else {
    row.set_dml(dml);
    row.set_first_dml(first_dml);
    if (is_sparse_) {
      row.is_sparse_row_ = true;
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < column_list_.count(); ++i) {
      const uint64_t column_id = column_list_.at(i).col_id_;
      ObObjType column_type = column_list_.at(i).col_type_.get_type();
      if (OB_SUCCESS != (ret = set_obj(column_type, column_id, seed, row.row_val_.cells_[i], trans_version))) {
        STORAGE_LOG(WARN, "fail to set obj.", K(ret), K(i), K(seed));
      } else {
        if (ObTinyTextType == column_type || ObTextType == column_type 
            || ObMediumTextType == column_type || ObLongTextType == column_type 
            || ObNVarchar2Type == column_type || ObNCharType == column_type
            || ObJsonType == column_type ) {
          row.row_val_.cells_[i].set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
          row.row_val_.cells_[i].set_collation_level(CS_LEVEL_IMPLICIT);
        } else if (ObVarcharType == column_type || ObCharType == column_type || ob_is_text_tc(column_type)) {
          row.row_val_.cells_[i].set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
          row.row_val_.cells_[i].set_collation_level(CS_LEVEL_IMPLICIT);
        } else if (ObNullType == column_type) {
          row.row_val_.cells_[i].set_collation_type(CS_TYPE_BINARY);
          row.row_val_.cells_[i].set_collation_level(CS_LEVEL_IGNORABLE);
        } else {
          row.row_val_.cells_[i].set_collation_type(CS_TYPE_BINARY);
          row.row_val_.cells_[i].set_collation_level(CS_LEVEL_NUMERIC);
        }
        // generate column id
        if (is_sparse_) {
          row.column_ids_[i] = column_id;
          STORAGE_LOG(INFO, "get next row", K(i), K(column_id));
        }
      }
    }
    row.flag_ = ObActionFlag::OP_ROW_EXIST;
    if (T_DML_DELETE == dml) {
      row.flag_ = ObActionFlag::OP_DEL_ROW;
    }

    STORAGE_LOG(INFO, "get next row", "column_count", column_list_.count(), K(row));
  }
  return ret;
}

int ObRowGenerate::set_obj(
    const ObObjType& column_type, const uint64_t column_id, const int64_t seed, ObObj& obj, const int64_t trans_version)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else {
    int64_t rowkey_pos = 0;
    int64_t value = 0;
    bool init_flag = false;
    if (is_multi_version_row_) {
      if (OB_HIDDEN_TRANS_VERSION_COLUMN_ID == column_id) {  // pos = 0 | value = -trans_version
        value = -trans_version;
        init_flag = true;
      } else if (OB_HIDDEN_SQL_SEQUENCE_COLUMN_ID == column_id) {  // pos = 0 | value = 0
        value = 0;
        init_flag = true;
      }
    }
    if (!init_flag) {
      rowkey_pos = schema_.get_column_schema(column_id)->get_rowkey_position();
      value = seed * column_type + column_id;
    }
    switch (column_type) {
      case ObNullType:
        if (rowkey_pos > 0) {
          ret = OB_NOT_SUPPORTED;
          STORAGE_LOG(WARN, "ObNULLType should not be rowkey column");
        } else {
          obj.set_null();
        }
        break;
      case ObTinyIntType:
        SET_VALUE(rowkey_pos, set_tinyint, int8_t, seed, value);
        break;
      case ObSmallIntType:
        SET_VALUE(rowkey_pos, set_smallint, int16_t, seed, value);
        break;
      case ObMediumIntType:
        SET_VALUE(rowkey_pos, set_mediumint, int32_t, seed, value);
        break;
      case ObInt32Type:
        SET_VALUE(rowkey_pos, set_int32, int32_t, seed, value);
        break;
      case ObIntType:
        SET_VALUE(rowkey_pos, set_int, int64_t, seed, value);
        break;
      case ObUTinyIntType:
        SET_VALUE(rowkey_pos, set_utinyint, uint8_t, seed, value);
        break;
      case ObUSmallIntType:
        SET_VALUE(rowkey_pos, set_usmallint, uint16_t, seed, value);
        break;
      case ObUMediumIntType:
        SET_VALUE(rowkey_pos, set_umediumint, uint32_t, seed, value);
        break;
      case ObUInt32Type:
        SET_VALUE(rowkey_pos, set_uint32, uint32_t, seed, value);
        break;
      case ObUInt64Type:
        SET_VALUE(rowkey_pos, set_uint64, uint64_t, seed, value);
        break;
      case ObFloatType:
        SET_VALUE(rowkey_pos, set_float, float, seed, value);
        break;
      case ObUFloatType:
        SET_VALUE(rowkey_pos, set_ufloat, float, seed, value);
        break;
      case ObDoubleType:
        SET_VALUE(rowkey_pos, set_double, double, seed, value);
        break;
      case ObUDoubleType:
        SET_VALUE(rowkey_pos, set_udouble, double, seed, value);
        break;
      case ObNumberType: {
        SET_NUMBER(p_allocator_, rowkey_pos, set_number, seed, value);
        break;
      }
      case ObUNumberType: {
        SET_NUMBER(p_allocator_, rowkey_pos, set_unumber, seed, value);
        break;
      }
      case ObDateType:
        SET_VALUE(rowkey_pos, set_date, int32_t, seed, value);
        break;
      case ObDateTimeType:
        SET_VALUE(rowkey_pos, set_datetime, int64_t, seed, value);
        break;
      case ObTimestampType:
        SET_VALUE(rowkey_pos, set_timestamp, int64_t, seed, value);
        break;
      case ObTimeType:
        SET_VALUE(rowkey_pos, set_time, int64_t, seed, value);
        break;
      case ObYearType:
        SET_VALUE(rowkey_pos, set_year, uint8_t, seed, value);
        break;
      case ObVarcharType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_varchar, seed, value);
        break;
      }
      case ObCharType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_char, seed, value);
        break;
      }
      case ObRawType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_raw, seed, value);
        break;
      }
      case ObEnumInnerType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_enum_inner, seed, value);
        break;
      }
      case ObSetInnerType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_set_inner, seed, value);
        break;
      }
      case ObNVarchar2Type: {
        SET_CHAR(p_allocator_, rowkey_pos, set_nvarchar2, seed, value);
        break;
      }
      case ObNCharType: {
        SET_CHAR(p_allocator_, rowkey_pos, set_nchar, seed, value);
        break;
      }
      case ObHexStringType: {
        char* buf = NULL;
        if (NULL == (buf = reinterpret_cast<char*>(p_allocator_->alloc(VARIABLE_BUF_LEN)))) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          STORAGE_LOG(WARN, "fail to alloc memory");
        } else if (rowkey_pos > 0) {
          snprintf(buf, 128, "%0127ld", seed);  // not change this
        } else {
          snprintf(buf, 128, "%0127ld", value);  // not change this
        }
        if (OB_SUCC(ret)) {
          ObString str;
          str.assign_ptr(buf, static_cast<int32_t>(strlen(buf)));
          obj.set_hex_string(str);
        }
        // SET_CHAR(p_allocator_, rowkey_pos, set_hex_string, seed, value);
        break;
      }
      case ObExtendType:
        if (rowkey_pos > 0) {
          ret = OB_NOT_SUPPORTED;
          STORAGE_LOG(WARN, "ObExtendType should not be rowkey column");
        } else {
          // TODO just set ObActionFlag::OP_NOP
          obj.set_nop_value();
        }
        break;
      case ObUnknownType:
        if (rowkey_pos > 0) {
          ret = OB_ERR_UNEXPECTED;
          STORAGE_LOG(WARN, "ObUnknownType should not be rowkey column");
        } else {
          obj.set_unknown(seed);
        }
        break;
      case ObTinyTextType:
      case ObTextType:
      case ObMediumTextType:
      case ObLongTextType: 
      case ObJsonType: {
        ObLobData* value = NULL;
        void* buf = NULL;
        if (OB_ISNULL(buf = p_allocator_->alloc(sizeof(ObLobData)))) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          STORAGE_LOG(WARN, "fail to allocate memory for ObLobData", K(ret));
        } else {
          ObLobIndex index;
          value = new (buf) ObLobData();
          value->idx_cnt_ = 10;
          for (int64_t i = 0; i < value->idx_cnt_; ++i) {
            ObLogicMacroBlockId logic_macro_id;
            logic_macro_id.data_seq_ = i;
            logic_macro_id.data_version_ = 1;
            index.byte_size_ = 1;
            index.char_size_ = 1;
            index.logic_macro_id_ = logic_macro_id;
            value->lob_idx_[i] = index;
            value->byte_size_ += index.byte_size_;
            value->char_size_ += index.char_size_;
          }
          obj.meta_.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
          obj.meta_.set_collation_level(CS_LEVEL_IMPLICIT);
          obj.set_type(column_type);
          obj.set_lob_value(column_type, value, value->get_handle_size());
        }
        break;
      }
      case ObBitType: {
        SET_VALUE(rowkey_pos, set_bit, uint64_t, seed, value);
        break;
      }
      case ObEnumType: {
        SET_VALUE(rowkey_pos, set_enum, uint64_t, seed, value);
        break;
      }
      case ObSetType: {
        SET_VALUE(rowkey_pos, set_set, uint64_t, seed, value);
        break;
      }
      case ObTimestampTZType: {
        obj.set_otimestamp_value(ObTimestampTZType, value, static_cast<uint16_t>(12));
        break;
      }
      case ObTimestampLTZType: {
        obj.set_otimestamp_value(ObTimestampLTZType, value, static_cast<uint16_t>(12));
        break;
      }
      case ObTimestampNanoType: {
        obj.set_otimestamp_value(ObTimestampNanoType, value, static_cast<uint16_t>(12));
        break;
      }
      case ObIntervalYMType: {
        obj.set_interval_ym(ObIntervalYMValue(value));
        break;
      }
      case ObIntervalDSType: {
        obj.set_interval_ds(ObIntervalDSValue(value, 14));
        break;
      }
      case ObNumberFloatType: {
        uint32_t digits = value;
        obj.set_number_float(ObNumber(3, &digits));
        break;
      }
      case ObURowIDType: {
        if (OB_FAIL(generate_urowid_obj(rowkey_pos, seed, value, obj))) {
          STORAGE_LOG(WARN, "fail to generate urowid obj");
        }
        break;
      }
      default:
        STORAGE_LOG(WARN, "not support this data type.", K(column_type));
        ret = OB_NOT_SUPPORTED;
    }
  }
  return ret;
}

int ObRowGenerate::check_one_row(const ObStoreRow& row, bool& exist)
{
  int ret = OB_SUCCESS;
  int64_t seed = -1;

  if (!is_inited_) {
    ret = OB_NOT_INIT;
    STORAGE_LOG(WARN, "should init first");
  } else {
    // first get seed from rowkey
    ObObjType column_type;
    int64_t pos = -1;
    uint64_t column_id = 0;
    ret = OB_ENTRY_NOT_EXIST;
    for (int64_t i = 0; i < column_list_.count(); ++i) {
      column_id = column_list_.at(i).col_id_;
      if (schema_.get_column_schema(column_id)->get_rowkey_position() > 0) {
        column_type = schema_.get_column_schema(column_id)->get_data_type();
        pos = i;
        ret = OB_SUCCESS;
        break;
      }
    }
    if (OB_SUCC(ret)) {
      // ObObj obj = row.row_val_.cells_[column_id];
      ObObj obj = row.row_val_.cells_[pos];
      if (OB_SUCCESS != (ret = get_seed(column_type, obj, seed))) {
        STORAGE_LOG(WARN, "fail to get seed.", K(ret));
      }
    }
  }
  // second compare the value
  if (OB_SUCC(ret)) {
    ObObjType column_type;
    int64_t value = 0;
    uint64_t column_id = 0;
    for (int64_t i = 0; i < column_list_.count(); ++i) {
      column_id = column_list_.at(i).col_id_;
      if (0 == schema_.get_column_schema(column_id)->get_rowkey_position()) {
        column_type = schema_.get_column_schema(column_id)->get_data_type();
        value = seed * static_cast<uint8_t>(column_type) + column_id;
        if (OB_SUCCESS != (ret = compare_obj(column_type, value, row.row_val_.cells_[i], exist))) {
          STORAGE_LOG(WARN, "compare obobj error", K(ret));
        }
        if (!exist) {
          break;
        }
      }
    }
  }
  return ret;
}

int ObRowGenerate::compare_obj(const ObObjType& column_type, const int64_t value, const ObObj obj, bool& exist)
{
  int ret = OB_SUCCESS;
  exist = true;

  switch (column_type) {
    case ObNullType:
      break;
    case ObTinyIntType:
      COMPARE_VALUE(get_tinyint, int8_t, value, exist);
      break;
    case ObSmallIntType:
      COMPARE_VALUE(get_smallint, int16_t, value, exist);
      break;
    case ObMediumIntType:
      COMPARE_VALUE(get_mediumint, int32_t, value, exist);
      break;
    case ObInt32Type:
      COMPARE_VALUE(get_int32, int32_t, value, exist);
      break;
    case ObIntType:
      COMPARE_VALUE(get_int, int64_t, value, exist);
      break;
    case ObUTinyIntType:
      COMPARE_VALUE(get_utinyint, uint8_t, value, exist);
      break;
    case ObUSmallIntType:
      COMPARE_VALUE(get_usmallint, uint16_t, value, exist);
      break;
    case ObUMediumIntType:
      COMPARE_VALUE(get_umediumint, uint32_t, value, exist);
      break;
    case ObUInt32Type:
      COMPARE_VALUE(get_uint32, uint32_t, value, exist);
      break;
    case ObUInt64Type:
      COMPARE_VALUE(get_uint64, uint64_t, value, exist);
      break;
    case ObFloatType:
      COMPARE_VALUE(get_float, float, value, exist);
      break;
    case ObUFloatType:
      COMPARE_VALUE(get_ufloat, float, value, exist);
      break;
    case ObDoubleType:
      COMPARE_VALUE(get_double, double, value, exist);
      break;
    case ObUDoubleType:
      COMPARE_VALUE(get_udouble, double, value, exist);
      break;
    case ObNumberType:
      COMPARE_NUMBER(p_allocator_, get_number, value, exist);
      break;
    case ObUNumberType:
      COMPARE_NUMBER(p_allocator_, get_unumber, value, exist);
      break;
    case ObDateType:
      COMPARE_VALUE(get_date, int32_t, value, exist);
      break;
    case ObDateTimeType:
      COMPARE_VALUE(get_datetime, int64_t, value, exist);
      break;
    case ObTimestampType:
      COMPARE_VALUE(get_timestamp, int64_t, value, exist);
      break;
    case ObTimeType:
      COMPARE_VALUE(get_time, int64_t, value, exist);
      break;
    case ObYearType:
      COMPARE_VALUE(get_year, uint8_t, value, exist);
      break;
    case ObVarcharType:
    case ObCharType:
    case ObRawType:
    case ObNVarchar2Type:
    case ObNCharType: {
      char* buf = NULL;
      if (NULL == (buf = reinterpret_cast<char*>(p_allocator_->alloc(VARIABLE_BUF_LEN)))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        STORAGE_LOG(WARN, "fail to alloc memory");
      } else {
        snprintf(buf, VARIABLE_BUF_LEN, "%064ld", value);
      }
      if (OB_SUCC(ret)) {
        ObString str;
        str.assign_ptr(buf, static_cast<int32_t>(strlen(buf)));
        if (str != obj.get_string()) {
          exist = false;
          STORAGE_LOG(WARN, "row value is different", K(str), K(obj));
        }
      }
      break;
    }
    case ObHexStringType: {
      char* buf = NULL;
      if (NULL == (buf = reinterpret_cast<char*>(p_allocator_->alloc(VARIABLE_BUF_LEN)))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        STORAGE_LOG(WARN, "fail to alloc memory");
      } else {
        snprintf(buf, VARIABLE_BUF_LEN, "%0127ld", value);  // not change this
      }
      if (OB_SUCC(ret)) {
        ObString str;
        str.assign_ptr(buf, static_cast<int32_t>(strlen(buf)));
        if (str != obj.get_string()) {
          exist = false;
          STORAGE_LOG(WARN, "row value is different", K(str), K(obj));
        }
      }
      break;
    }
    case ObExtendType:
      // just check value to OP_NOP
      if (obj.get_ext() != ObActionFlag::OP_NOP) {
        exist = false;
        STORAGE_LOG(WARN, "row value is different", K(obj.get_ext()), K(static_cast<int64_t>(value)));
      }
      break;
    case ObTinyTextType:
    case ObTextType:
    case ObMediumTextType:
    case ObLongTextType:
    case ObJsonType: {
      break;
    }
    case ObBitType: {
      COMPARE_VALUE(get_bit, uint64_t, value, exist);
      break;
    }
    case ObEnumType: {
      COMPARE_VALUE(get_enum, uint64_t, value, exist);
      break;
    }
    case ObSetType: {
      COMPARE_VALUE(get_set, uint64_t, value, exist);
      break;
    }
    case ObTimestampTZType:
    case ObTimestampLTZType:
    case ObTimestampNanoType: {
      exist = (value == obj.get_otimestamp_value().time_us_);
      break;
    }
    case ObIntervalYMType: {
      exist = (value == obj.get_interval_ym().nmonth_);
      break;
    }
    case ObIntervalDSType: {
      exist = (value == obj.get_interval_ds().nsecond_);
      break;
    }
    case ObNumberFloatType: {
      exist = (value == *obj.get_number_float().get_digits());
      break;
    }
    case ObURowIDType: {
      ObObj urowid_obj;
      int64_t rowkey_pos = 0;
      int64_t seed = 0;
      if (OB_FAIL(generate_urowid_obj(rowkey_pos, seed, value, urowid_obj))) {
        STORAGE_LOG(WARN, "fail to generate urowid obj", K(ret), K(value));
      } else {
        exist = (urowid_obj == obj);
      }
      break;
    }
    default:
      STORAGE_LOG(WARN, "don't support this data type.", K(column_type));
      ret = OB_NOT_SUPPORTED;
  }
  return ret;
}

int ObRowGenerate::get_seed(const ObObjType& column_type, const ObObj obj, int64_t& seed)
{
  int ret = OB_SUCCESS;
  switch (column_type) {
    case ObTinyIntType:
      seed = static_cast<int64_t>(obj.get_tinyint());
      break;
    case ObSmallIntType:
      seed = static_cast<int64_t>(obj.get_smallint());
      break;
    case ObMediumIntType:
      seed = static_cast<int64_t>(obj.get_mediumint());
      break;
    case ObInt32Type:
      seed = static_cast<int64_t>(obj.get_int32());
      break;
    case ObIntType:
      seed = obj.get_int();
      break;
    case ObUTinyIntType:
      seed = static_cast<int64_t>(obj.get_utinyint());
      break;
    case ObUSmallIntType:
      seed = static_cast<int64_t>(obj.get_usmallint());
      break;
    case ObUMediumIntType:
      seed = static_cast<int64_t>(obj.get_umediumint());
      break;
    case ObUInt32Type:
      seed = static_cast<int64_t>(obj.get_uint32());
      break;
    case ObUInt64Type:
      seed = static_cast<int64_t>(obj.get_uint64());
      break;
    case ObFloatType:
    case ObUFloatType:
      seed = static_cast<int64_t>(obj.get_float());
      break;
    case ObDoubleType:
    case ObUDoubleType:
      seed = static_cast<int64_t>(obj.get_double());
      break;
    case ObNumberType: {
      const char* value = obj.get_number().format();
      seed = static_cast<int64_t>(strtoll(value, NULL, 10));
      break;
    }
    case ObUNumberType: {
      const char* value = obj.get_unumber().format();
      seed = static_cast<int64_t>(strtoll(value, NULL, 10));
      break;
    }
    case ObDateType:
      seed = static_cast<int64_t>(obj.get_date());
      break;
    case ObDateTimeType:
      seed = static_cast<int64_t>(obj.get_datetime());
      break;
    case ObTimestampType:
      seed = static_cast<int64_t>(obj.get_timestamp());
      break;
    case ObTimeType:
      seed = static_cast<int64_t>(obj.get_time());
      break;
    case ObYearType:
      seed = static_cast<int64_t>(obj.get_year());
      break;
    case ObVarcharType:
    case ObCharType:
    case ObHexStringType:
    case ObRawType:
      seed = static_cast<int64_t>(strtoll(obj.get_string().ptr(), NULL, 10));
      break;
    case ObURowIDType: {
      ObURowIDData urowid_data;
      ObSEArray<ObObj, 2> obj_arr;
      if (OB_FAIL(obj.get_urowid(urowid_data))) {
        STORAGE_LOG(WARN, "fail to get urowid", K(ret), K(obj));
      } else if (OB_FAIL(urowid_data.get_pk_vals(obj_arr))) {
        STORAGE_LOG(WARN, "fail to get pk vals", K(ret), K(obj));
      } else if (OB_UNLIKELY(2 != obj_arr.count()) || OB_UNLIKELY(!obj_arr.at(0).is_int())) {
        ret = OB_ERR_UNEXPECTED;
        STORAGE_LOG(WARN, "unexpected obj count or obj type", K(ret), K(obj_arr));
      } else {
        seed = obj_arr.at(0).get_int();
      }
      break;
    }
    case ObExtendType:
    default:
      STORAGE_LOG(WARN, "don't support this data type.", K(column_type));
      ret = OB_NOT_SUPPORTED;
  }
  return ret;
}

int ObRowGenerate::generate_urowid_obj(
    const int64_t rowkey_pos, const int64_t seed, const int64_t value, ObObj& urowid_obj)
{
  int ret = OB_SUCCESS;
  int64_t real_value = rowkey_pos > 0 ? seed : value;
  ObObj int_obj;
  int_obj.set_int(real_value);
  ObObj str_obj;
  char* buf = NULL;
  if (OB_ISNULL(p_allocator_)) {
    ret = OB_INVALID_ARGUMENT;
    STORAGE_LOG(WARN, "alloc is NULL");
  } else if (OB_ISNULL(buf = reinterpret_cast<char*>(p_allocator_->alloc(VARIABLE_BUF_LEN)))) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    STORAGE_LOG(WARN, "fail to alloc memory");
  } else {
    snprintf(buf, VARIABLE_BUF_LEN, "%064ld", real_value);
    str_obj.set_varchar(buf, static_cast<int32_t>(strlen(buf)));
    str_obj.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
  }
  if (OB_SUCC(ret)) {
    common::ObURowIDData urowid_data;
    ObSEArray<ObObj, 2> obj_arr;
    if (OB_FAIL(obj_arr.push_back(int_obj)) || OB_FAIL(obj_arr.push_back(str_obj))) {
      STORAGE_LOG(WARN, "fail to push back obj", K(ret), K(int_obj), K(str_obj));
    } else if (OB_FAIL(urowid_data.set_rowid_content(obj_arr, ObURowIDData::PK_ROWID_VERSION, *p_allocator_))) {
      STORAGE_LOG(WARN, "fail to setup urowid content", K(ret), K(obj_arr));
    } else {
      urowid_obj.set_urowid(urowid_data);
    }
  }
  return ret;
}

}  // namespace blocksstable
}  // namespace oceanbase
